#pragma once

#include <semaphore.h>
#include <iostream>
#include <pthread.h>
using namespace std;
#include <vector>

#include "MyMute.hpp"
#include "MySem.hpp"

namespace RingBufferModule
{
    using namespace MyMutexModule;
    using namespace MySemModule;

    const int g_default_cap = 10;

    template <class T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap = g_default_cap)
            : _ring(cap)
            , _cap(cap)
            , _c_head(0)
            , _p_tail(0)
            , _space_sem(cap)   // 初始化空间信号量
            , _data_sem(0)      // 初始化数据信号量
        {
            // sem_init(&_data_sem, 0, 0);     // 初始化数据信号量
            // sem_init(&_space_sem, 0, _cap); // 初始化空间信号量
        }

        void Push(T &data)
        {
            // 1. 先获取信号量  -->有，获取成功；没有，阻塞
            // sem_wait(&_space_sem);
            _space_sem.P();

            // 多生产者时，不上锁，会造成空间数据的丢失（覆盖）
            {
                LockGuard lockguard(_space_lock);

                _ring[_p_tail] = data;
                _p_tail++;
                _p_tail %= _cap;
            }
            // sem_post(&_data_sem); // 数据信号量增加
            _data_sem.V();
        }

        void Pop(T *out)
        {
            // sem_wait(&_data_sem);
            _data_sem.P();

            // 多消费者时，不上锁，会造成空间数据的重复消费
            {
                LockGuard lockguard(_data_lock);

                *out = _ring[_c_head];
                _c_head++;
                _c_head %= _cap;
            }

            _space_sem.V();
            // sem_post(&_space_sem); // 空间信号量增加
        }

        ~RingBuffer()
        {
            // sem_destroy(&_data_sem);
            // sem_destroy(&_space_sem);
        }

    private:
        vector<T> _ring; // 环，临界资源
        int _cap;        // 总容量
        int _c_head;
        int _p_tail;

        Sem _data_sem;  // 数据信号量
        Sem _space_sem; // 空间信号量

        Mutex _space_lock; // 空间锁
        Mutex _data_lock;  // 数据锁
    };

} // namespace RingBufferModule
